//****************************************/
//* mImage 03052011                      */
//* Riku Maikola rpm@ac-mapa.org         */
//****************************************/
#include"mImage.h"

Image::Image()
{
};

uint Image::IsType()
{
    return type;
};
void Image::SetType(uint a)
{
    type = a;
};

//***************************************************//
mPointArray Image::Ray(int alfa,mPoint p1,mPoint p2)
{
    mPointArray p3;
    ME[alfa]->Intersection(&p3,eR(p1,p2));
    return p3;
}

//**************************************************************************************************//
//**                                                                                              **//
//**                      eLine ADD                                                               **//
//**                                                                                              **//
//**************************************************************************************************//
bool Image::add(eLine el)
{
    for(uint a=0; a<ME.size(); a++)
    {
        if( ME[a]->Match(eL(el.p1(),el.p2())))return true;
    }

    element * El = new eLine;
    *El = el;

    test(El->H);
    test(El->L);

    ME.push_back( El);
    updated=true;
    return true;
}

//***********************************//
//**                               **//
//***********************************//
bool Image::add( eArc el )
{
    for(uint a=0; a<ME.size(); a++)
    {
        if( ME.at(a)->Match( eA( el.cp() ,el.a1,el.a2,el.r) ))return true;
    }

    element * El = new eArc;
    *El = el;

    test(El->H);
    test(El->L);
    ME.push_back(El);
    updated=true;
    return true;
};

//***********************************//
//**                               **//
//***********************************//
bool Image::add(eCircle el)
{
    //CHECK FOR DOUBLES
    for(uint a=0; a<ME.size(); a++)
    {
        if( ME.at(a)->Match( eC( el.cp(),el.r) ))return true;
    }

    element * El = new eCircle;
    *El = el;

    test(El->H);
    test(El->L);
    ME.push_back(El);
    updated=true;
    return true;
}

//***********************************//
//**                               **//
//***********************************//
bool Image::add(eTriangle el)
{
    //CHECK FOR DOUBLES
    /*for(uint a=0; a<ME.size(); a++)
    {
        if( ME.at(a)->Match( eC( el.cp(),el.r) ))return true;
    }*/

    element * El = new eTriangle;
    *El = el;

    test(El->H);
    test(El->L);
    ME.push_back(El);
    updated=true;
    SetType(m_Mesh);
    return true;
}
//***************************************//
//**    box                            **//
//***************************************//

bool Image::Box(mPoint p1,mPoint p2)
{
    add(eL(mP(p1.x,p1.y),mP(p1.x,p2.y)));
    add(eL(mP(p1.x,p2.y),mP(p2.x,p2.y)));
    add(eL(mP(p2.x,p2.y),mP(p2.x,p1.y)));
    add(eL(mP(p2.x,p1.y),mP(p1.x,p1.y)));
    return true;
}

//***********************************//
//**                               **//
//***********************************//
bool Image::Swap( uint E1 , uint E2)
{
    if( ME.size() == 0)return true;
    if((ME.size()-1) < E1)return true;
    if((ME.size()-1) < E2)return true;

    std::swap( ME[E1] , ME[E2] );
    updated=true;
    return true;
}

//***********************************//
//**                               **//
//***********************************//
bool Image::Del()
{
    for(uint a=0; a<ME.size(); a++)
    {
        if(ME.at(a)->F() == 1)
        {
            ME.erase(ME.begin()+a);
            a=-1;
        }
    }

    ClearArea();
    for(uint a=0; a<ME.size(); a++)
    {
        test(ME[a]->H);
        test(ME[a]->L);
    }
    updated=true;
    return true;
}
//***********************************//
//**                               **//
//***********************************//
bool Image::Select(uint a)
{
    if(a>=ME.size())return false;


    if(ME.at(a)->F() == 1)
        ME.at(a)->flag = 0;
    else
        ME.at(a)->flag = 1;

    updated=true;
    return true;
}
//***********************************//
//**
//***********************************//
bool Image::SelectArea(mPoint p1,mPoint p2)
{
    mArea ALUE;
    ALUE.test(p1);
    ALUE.test(p2);

    //************************//
    for(uint a=0; a<ME.size(); a++)
    {
        if(ME.at(a)->IsAreaInSide(ALUE))
            ME.at(a)->flag = 1;
    }

    updated=true;
    return true;
}

bool Image::SelectALL()
{
    for(uint a=0; a<ME.size(); a++)
        ME.at(a)->flag = 1;

    updated=true;
    return true;
}
//***********************************//
//**      SelectConnect            **//
//***********************************//
bool Image::SelectConnected()
{
BACK:
    bool t=false;
    for(uint a=0; a<ME.size(); a++)
    {
        for(uint b=0; b<ME.size(); b++)
        {
            if(ME.at(a)->p1().Match(ME.at(b)->p2()))
            {
                if((ME.at(a)->F()==0 && ME.at(b)->F()==1))
                {
                    ME.at(a)->flag = 1;
                    ME.at(b)->flag = 1;
                    t=true;
                }
                if((ME.at(a)->F()==1 && ME.at(b)->F()==0))
                {
                    ME.at(a)->flag = 1;
                    ME.at(b)->flag = 1;
                    t=true;
                }
            }
            if(ME.at(a)->p2().Match(ME.at(b)->p1()))
            {
                if((ME.at(a)->F()==0 && ME.at(b)->F()==1))
                {
                    ME.at(a)->flag = 1;
                    ME.at(b)->flag = 1;
                    t=true;
                }
                if((ME.at(a)->F()==1 && ME.at(b)->F()==0))
                {
                    ME.at(a)->flag = 1;
                    ME.at(b)->flag = 1;
                    t=true;
                }
            }
            if(ME.at(a)->p2().Match(ME.at(b)->p2()))
            {
                if((ME.at(a)->F()==0 && ME.at(b)->F()==1))
                {
                    ME.at(a)->flag = 1;
                    ME.at(b)->flag = 1;
                    t=true;
                }
                if((ME.at(a)->F()==1 && ME.at(b)->F()==0))
                {
                    ME.at(a)->flag = 1;
                    ME.at(b)->flag = 1;
                    t=true;
                }
            }
            if(ME.at(a)->p1().Match(ME.at(b)->p1()))
            {
                if((ME.at(a)->F()==0 && ME.at(b)->F()==1))
                {
                    ME.at(a)->flag = 1;
                    ME.at(b)->flag = 1;
                    t=true;
                }
                if((ME.at(a)->F()==1 && ME.at(b)->F()==0))
                {
                    ME.at(a)->flag = 1;
                    ME.at(b)->flag = 1;
                    t=true;
                }
            }
        }
    }
    if(t)goto BACK;

    updated=true;
    return true;
}
//***********************************//
//**      DeselectAll              **//
//***********************************//
bool Image::DeselectAll()
{
    for(uint a=0; a<ME.size(); a++)
        ME.at(a)->flag = 0;

    updated=true;
    return true;
}


double Image::Distance(mPoint P)
{
    double D=NAN;

    for(uint a=0; a<ME.size(); a++)
    {
        double DT = ME.at(a)->Distance(P.x,P.y);
        if(DT<D || isnan(D))
            D=DT;
    }
    return D;
}

//Get Layer Color
/*
PenToColorMapEntry_t( 0, RGB( 255, 255, 255 ) ),
PenToColorMapEntry_t( 1, RGB( 255, 0, 0 ) ),
PenToColorMapEntry_t( 2, RGB( 255, 255, 0 ) ),
PenToColorMapEntry_t( 3, RGB( 0, 255, 0 ) ),
PenToColorMapEntry_t( 4, RGB( 0, 255, 255 ) ),
PenToColorMapEntry_t( 5, RGB( 0, 0, 255 ) ),
PenToColorMapEntry_t( 6, RGB( 255, 0, 255 ) ),
PenToColorMapEntry_t( 7, RGB( 0, 0, 0 ) ),
PenToColorMapEntry_t( 8, RGB( 128, 128, 128 ) ),
PenToColorMapEntry_t( 9, RGB( 190, 190, 190 ) ),
PenToColorMapEntry_t( 11, RGB( 255, 123, 123 ) ),
PenToColorMapEntry_t( 21, RGB( 255, 156, 123 ) ),
PenToColorMapEntry_t( 31, RGB( 255, 189, 123 ) ),
PenToColorMapEntry_t( 41, RGB( 255, 222, 183 ) ),
PenToColorMapEntry_t( 51, RGB( 255, 255, 123 ) ),
PenToColorMapEntry_t( 61, RGB( 222, 255, 123 ) ),
PenToColorMapEntry_t( 71, RGB( 189, 255, 123 ) ),
PenToColorMapEntry_t( 81, RGB( 156, 255, 123 ) ),
PenToColorMapEntry_t( 91, RGB( 123, 255, 123 ) ),
PenToColorMapEntry_t( 101, RGB( 122, 255, 156 ) ),
PenToColorMapEntry_t( 111, RGB( 123, 255, 189 ) ),
PenToColorMapEntry_t( 121, RGB( 123, 255, 222 ) ),
PenToColorMapEntry_t( 131, RGB( 123, 255, 255 ) ),
PenToColorMapEntry_t( 141, RGB( 123, 222, 255 ) ),
PenToColorMapEntry_t( 151, RGB( 123, 189, 255 ) ),
PenToColorMapEntry_t( 161, RGB( 123, 156, 255 ) ),
PenToColorMapEntry_t( 171, RGB( 123, 123, 255 ) ),
PenToColorMapEntry_t( 181, RGB( 156, 123, 255 ) ),
PenToColorMapEntry_t( 191, RGB( 189, 123, 255 ) ),
PenToColorMapEntry_t( 201, RGB( 222, 123, 255 ) ),
PenToColorMapEntry_t( 211, RGB( 255, 123, 255 ) ),
PenToColorMapEntry_t( 221, RGB( 255, 123, 222 ) ),
PenToColorMapEntry_t( 231, RGB( 255, 123, 189 ) ),
PenToColorMapEntry_t( 241, RGB( 255, 123, 156 ) ),
PenToColorMapEntry_t( 251, RGB( 41, 41, 41 ) ),
PenToColorMapEntry_t( 252, RGB( 90, 90, 90 ) ),
PenToColorMapEntry_t( 253, RGB( 136, 136, 136 ) ),
PenToColorMapEntry_t( 254, RGB( 181, 181, 181 ) ),
*/


//*******************************//
//**                           **//
//*******************************//
mPointArray Image::IntImgRay(mPoint p1,mPoint p2)
{
    mPointArray T;
    for(uint a=0; a<ME.size(); a++)
    {
        ME.at(a)->Intersection(&T,eR(p1,p2));
    }
    return T;
}

//*******************************//
//**                           **//
//*******************************//
bool Image::Copy(Image * I,mPoint P)
{
    uint S=ME.size();

    for(uint t=0; t<S; t++)
    {
        //LINE LINE....
        if(ME.at(t)->T()==1)
        {
            I->add( eL(mP(ME.at(t)->p1().x+P.x,ME.at(t)->p1().y+P.y,ME.at(t)->p1().z+P.z),
                       mP(ME.at(t)->p2().x+P.x, ME.at(t)->p2().y+P.y,ME.at(t)->p2().z+P.z
                         )));
        }

        if(ME.at(t)->T()==3)
        {
            I->add( eA( mP(ME.at(t)->cp().x+P.x,
                           ME.at(t)->cp().y+P.y),
                        ME.at(t)->a1,
                        ME.at(t)->a2,
                        ME.at(t)->r));
        }

        if(ME.at(t)->T()==4)
        {
            I->add( eC( mP(ME.at(t)->cp().x+P.x,
                           ME.at(t)->cp().y+P.y,
                           ME.at(t)->cp().z+P.z),
                        ME.at(t)->r));
        }
    }
    return true;
}

//*******************************//
//**                           **//
//*******************************//
bool Image::Clear()
{
    for ( uint i = 0; i < ME.size(); i++ )
    {
        delete ME[i];
    }

    ClearArea();
    ME.clear();
    type = m_Image;

    updated=true;
    return true;
}
//*******************************//
//**                           **//
//*******************************//
bool Image::CopySelected(Image * I,mPoint P)
{
    uint S=ME.size();

    for(uint t=0; t<S; t++)
    {
        //LINE LINE....
        if(ME.at(t)->T()==1 && ME.at(t)->F()==1)
        {
            I->add( eL( ME.at(t)->p1()+P,ME.at(t)->p2()+P));
        }

        if(ME.at(t)->T()==3 && ME.at(t)->F()==1)
        {
            I->add( eA( ME.at(t)->cp()+P,
                        ME.at(t)->a1,
                        ME.at(t)->a2,
                        ME.at(t)->r));
        }

        if(ME.at(t)->T()==4 && ME.at(t)->F()==1)
        {
            I->add( eC( ME.at(t)->cp()+P,ME.at(t)->r));
        }
    }
    I->updated=true;
    return true;
}

bool Image::Rotate(double R)
{
    for(uint a=0; a<ME.size(); a++)
    {
        ME.at(a)->RotateZ(R);

        if(ME.at(a)->T()==e_Circle)
        {
            ME.at(a)->at(0) = ME.at(a)->at(2)+mP(ME.at(a)->r,0);
            ME.at(a)->at(1) = ME.at(a)->at(2)+mP(ME.at(a)->r,0);
        }


        ME.at(a)->a1 += R;
        ME.at(a)->a2 += R;

        ME.at(a)->cArea();
    }
    updated=true;
    return true;
};
void Image::MirrorX()
{
    uint s = ME.size();

    for(uint a=0; a<s; a++)
    {
        if( ME.at(a)->T()==1 )
        {
            add( eL(mP(-ME.at(a)->p1().x, ME.at(a)->p1().y,  ME.at(a)->p1().z),mP(-ME.at(a)->p2().x, ME.at(a)->p2().y,  ME.at(a)->p2().z)));
        }
        if( ME.at(a)->T()==3)
        {
            add( eA(mP(-ME.at(a)->cp().x,ME.at(a)->cp().y,ME.at(a)->cp().z),

                    mP(-ME.at(a)->cp().x,ME.at(a)->cp().y,ME.at(a)->cp().z).GetDirectionXY(mP(-ME.at(a)->p2().x,ME.at(a)->p2().y,ME.at(a)->p2().z)),
                    mP(-ME.at(a)->cp().x,ME.at(a)->cp().y,ME.at(a)->cp().z).GetDirectionXY(mP(-ME.at(a)->p1().x,ME.at(a)->p1().y,ME.at(a)->p1().z)),

                    ME.at(a)->r   ));
        }

        if( ME.at(a)->T()==4)
        {
            add( eC(mP(-ME.at(a)->cp().x,
                       ME.at(a)->cp().y,
                       ME.at(a)->cp().z),
                    ME.at(a)->r));
        }

    }
}

bool Image::Move(mPoint P)
{
    L += P;
    H += P;

    for(uint a=0; a<ME.size(); a++)
    {
        ME.at(a)->Translate(P);
        ME.at(a)->L += P;
        ME.at(a)->H += P;
    }
    updated=true;
    return true;
}


//**************************************************
//**
//**************************************************
bool Image::MoveRight()
{
    mArea pos;
    bool Hi=false;
    for(uint a=0; a<ME.size(); a++)
    {
        if((ME[a]->F() == 1))
        {
            Hi=true;
            pos.test(mP(ME[a]->L.x, ME[a]->H.y));
        }
    }
    if(Hi)Move(mP(-pos.L.x,0));
    updated=true;
    return true;
}

bool Image::MoveLeft()
{
    mArea pos;
    bool Hi=false;
    for(uint a=0; a<ME.size(); a++)
    {
        if((ME[a]->F() == 1))
        {
            Hi = true;
            pos.test(mP(ME[a]->H.x, ME[a]->H.y));
        }
    }
    if(Hi)Move(mP(-pos.H.x,0));
    updated=true;
    return true;
}
bool Image::MoveDown()
{
    mArea pos;
    bool Hi=false;
    for(uint a=0; a<ME.size(); a++)
    {
        if((ME[a]->F() == 1))
        {
            Hi = true;
            pos.test(mP(0, ME[a]->H.y));
        }
    }
    if(Hi)Move(mP(0,-pos.H.y));
    updated=true;
    return true;
}
bool Image::MoveUp()
{
    mArea pos;
    bool Hi=false;
    for(uint a=0; a<ME.size(); a++)
    {
        if((ME[a]->F() == 1))
        {
            Hi = true;
            pos.test(mP( 0, ME[a]->L.y));
        }
    }
    if(Hi)Move(mP(0,-pos.L.y));
    updated=true;
    return true;
}

bool Image::MoveVerticalCenter()
{
    mArea pos;
    bool Hi=false;
    for(uint a=0; a<ME.size(); a++)
    {
        if((ME[a]->F() == 1))
        {
            Hi=true;
            pos.test(mP(ME[a]->H.x, ME[a]->H.y));
            pos.test(mP(ME[a]->L.x, ME[a]->L.y));
        }
    }
    if(Hi)Move(-mP((pos.H.x-pos.L.x)/2+ pos.L.x,0));
    updated=true;
    return true;
}
bool Image::MoveHorizontalCenter()
{
    mArea pos;
    bool HI=false;
    for(uint a=0; a<ME.size(); a++)
    {
        if((ME[a]->F() == 1))
        {
            HI=true;
            pos.test(mP(ME[a]->H.x, ME[a]->H.y));
            pos.test(mP(ME[a]->L.x, ME[a]->L.y));
        }
    }
    if(HI)Move(-mP(0,(pos.H.y-pos.L.y)/2+ pos.L.y,0));
    updated=true;
    return true;
}


bool Image::MoveSelected(mPoint P)
{
    uint S=ME.size();

    for(uint t=0; t<S; t++)
    {
        //LINE LINE....
        if(ME.at(t)->T()==1 && ME.at(t)->F()==1)
        {
            add( eL( ME.at(t)->p1()+P,ME.at(t)->p2()+P));
        }

        if(ME.at(t)->T()==3 && ME.at(t)->F()==1)
        {
            add( eA( ME.at(t)->cp()+P,
                     ME.at(t)->a1,
                     ME.at(t)->a2,
                     ME.at(t)->r));
        }

        if(ME.at(t)->T()==4 && ME.at(t)->F()==1)
        {
            add( eC( ME.at(t)->cp()+P,ME.at(t)->r));
        }
    }
    Del();
    updated=true;
    return true;
}
//**************************************************
//** IF CHAIN THEN FLIP
//**************************************************
bool Image::Flip()
{
    if(ME.size()==0) return false;
    if(!type == m_Chain)return false;

    uint PO1[ ME.size() ];
    uint PO2[ ME.size() ];

    for(uint a=0 ; a<ME.size(); a++)
    {
        PO1[a]=0;
        PO2[a]=0;
        for(uint b=0 ; b<ME.size(); b++)
        {
            if(ME[a]->p1().Match(ME[b]->p1()))PO1[a]++;
            if(ME[a]->p1().Match(ME[b]->p2()))PO1[a]++;
            if(ME[a]->p2().Match(ME[b]->p1()))PO2[a]++;
            if(ME[a]->p2().Match(ME[b]->p2()))PO2[a]++;
        }
        if( PO1[a]>2 ) return false;
        if( PO2[a]>2 ) return false;
    }

    uint SO=0,ST=0;

    for(uint a=0 ; a<ME.size(); a++)
    {
        if(PO1[a]==1)
        {
            ST=a;

            SO++;
        }
        if(PO2[a]==1)
        {
            ST=a;
            SO++;
        }
    }


    if(SO>2)return false;

    Swap(0,ST);

    for(uint a=1 ; a<ME.size(); a++)
    {
        for(uint b=a ; b<ME.size(); b++)
        {
            if(ME[a-1]->p1().Match(ME[b]->p1()))
            {
                Swap(a,b);
                ME[a-1]->direction = false;
                ME[a]->direction = true;
                break;
            }
            if(ME[a-1]->p1().Match(ME[b]->p2()))
            {
                Swap(a,b);
                ME[a-1]->direction = false;
                ME[a]->direction = false;
                break;
            }

            if(ME[a-1]->p2().Match(ME[b]->p1()))
            {
                Swap(a,b);
                ME[a-1]->direction = true;
                ME[a]->direction = true;
                break;
            }
            if(ME[a-1]->p2().Match(ME[b]->p2()))
            {
                Swap(a,b);
                ME[a-1]->direction = true;
                ME[a]->direction = false;
                break;
            }
        }
    }
    updated=true;
    return true;
}

//**********
bool Image::MakeChain()
{
    if(ME.size()==0) return false;

    uint PO1[ ME.size() ];
    uint PO2[ ME.size() ];

    for(uint a=0 ; a<ME.size(); a++)
    {
        PO1[a]=0;
        PO2[a]=0;
        for(uint b=0 ; b<ME.size(); b++)
        {
            if(ME[a]->p1().Match(ME[b]->p1()))PO1[a]++;
            if(ME[a]->p1().Match(ME[b]->p2()))PO1[a]++;
            if(ME[a]->p2().Match(ME[b]->p1()))PO2[a]++;
            if(ME[a]->p2().Match(ME[b]->p2()))PO2[a]++;
        }
        if( PO1[a]>2 ) return false;
        if( PO2[a]>2 ) return false;
    }

    uint SO=0,ST=0;

    for( uint a=(ME.size()-1); a<1600000 ; a--)
    {
        if(PO1[a]==1)
        {
            ST=a;

            SO++;
        }
        if(PO2[a]==1)
        {
            ST=a;
            SO++;
        }
    }


    if(SO>2)return false;

    Swap(0,ST);

    for(uint a=1 ; a<ME.size(); a++)
    {
        for(uint b=a ; b<ME.size(); b++)
        {
            if(ME[a-1]->p1().Match(ME[b]->p1()))
            {
                Swap(a,b);
                ME[a-1]->direction = false;
                ME[a]->direction = true;
                break;
            }
            if(ME[a-1]->p1().Match(ME[b]->p2()))
            {
                Swap(a,b);
                ME[a-1]->direction = false;
                ME[a]->direction = false;
                break;
            }

            if(ME[a-1]->p2().Match(ME[b]->p1()))
            {
                Swap(a,b);
                ME[a-1]->direction = true;
                ME[a]->direction = true;
                break;
            }
            if(ME[a-1]->p2().Match(ME[b]->p2()))
            {
                Swap(a,b);
                ME[a-1]->direction = true;
                ME[a]->direction = false;
                break;
            }
        }
    }

    type = m_Chain;
    updated=true;
    return true;
}

//************************************************//
bool Image::Lathe(DrawBuffer * DB)
{
    if(updated)
    {

        if(!MakeChain())return false;

        if(P1(0).y < P2(Size()-1).y)
        {
            Flip();  //should reverse direction:)
        }
        DB->Clear();
        vertex ney;
        double step=TAU/20;

        for(uint e=0 ; e<ME.size(); e++)
        {
            vertex ney;
            mPointArray P = ME[e]->ToArray(0.01);

            if(P.size()<2)return false;

            mPoint np1 = mP(0,0),np2 = mP(0,0);

            for(uint a=0; a<P.size()-1; a++)
            {
                if(T(e)==1)
                {
                    np1 = mP(0,0).GetFromPoint( P1(e).GetDirectionXY(P2(e))+(PI/2) , 1) ;
                    np2 = mP(0,0).GetFromPoint( P1(e).GetDirectionXY(P2(e))+(PI/2) , 1) ;          //NORMAL...........

                }
                if(T(e)==2)
                {
                    np1 = mP(0,0).GetFromPoint( PC(e).GetDirectionXY(P[a] ), 1) ;
                    np2 = mP(0,0).GetFromPoint( PC(e).GetDirectionXY(P[a+1]) , 1) ;          //NORMAL...........
                }

                if(T(e)==3)
                {
                    np1 = mP(0,0).GetFromPoint( PC(e).GetDirectionXY(P[a] ), -1) ;
                    np2 = mP(0,0).GetFromPoint( PC(e).GetDirectionXY(P[a+1]) , -1) ;          //NORMAL...........
                }
                for(double r=0; r<TAU; r=r+step)
                {
                    mPoint p1 = P[a].RotateY_out(r);
                    mPoint p2 = P[a+1].RotateY_out(r);
                    mPoint p3 = P[a].RotateY_out(r+step);
                    mPoint p4 = P[a+1].RotateY_out(r+step);

                    mPoint nop1 = np1.RotateY_out(r);
                    mPoint nop2 = np2.RotateY_out(r);
                    mPoint nop3 = np1.RotateY_out(r+step);
                    mPoint nop4 = np2.RotateY_out(r+step);

                    //POLYGON
                    ney.x = p1.x;
                    ney.y = p1.z;
                    ney.z = p1.y;
                    ney.nx = nop1.x;
                    ney.ny = nop1.z;
                    ney.nz = nop1.y;
                    ney.r = 1;
                    ney.g = 0;
                    ney.b = 0;
                    DB->vbuf.push_back(ney);

                    ney.x = p2.x;
                    ney.y = p2.z;
                    ney.z = p2.y;
                    ney.nx = nop2.x;
                    ney.ny = nop2.z;
                    ney.nz = nop2.y;
                    ney.r = 1;
                    ney.g = 0;
                    ney.b = 0;
                    DB->vbuf.push_back(ney);

                    ney.x = p3.x;
                    ney.y = p3.z;
                    ney.z = p3.y;
                    ney.nx = nop3.x;
                    ney.ny = nop3.z;
                    ney.nz = nop3.y;
                    ney.r = 1;
                    ney.g = 0;
                    ney.b = 0;
                    DB->vbuf.push_back(ney);

                    //POLYGON
                    ney.x = p2.x;
                    ney.y = p2.z;
                    ney.z = p2.y;
                    ney.nx = nop2.x;
                    ney.ny = nop2.z;
                    ney.nz = nop2.y;
                    ney.r = 0;
                    ney.g = 0;
                    ney.b = 0;
                    DB->vbuf.push_back(ney);

                    ney.x = p4.x;
                    ney.y = p4.z;
                    ney.z = p4.y;
                    ney.nx = nop4.x;
                    ney.ny = nop4.z;
                    ney.nz = nop4.y;
                    ney.r = 0;
                    ney.g = 0;
                    ney.b = 0;
                    DB->vbuf.push_back(ney);

                    ney.x = p3.x;
                    ney.y = p3.z;
                    ney.z = p3.y;
                    ney.nx = nop3.x;
                    ney.ny = nop3.z;
                    ney.nz = nop3.y;
                    ney.r = 0;
                    ney.g = 0;
                    ney.b = 0;
                    DB->vbuf.push_back(ney);
                }
            }
        }
        DB->Set( GL_TRIANGLES , 4 , true);
        updated=false;
        return true;
    }
    return false;
}
//************************************************//
bool Image::Refresh(DrawBuffer *buff)
{
    if(updated)
    {
        //new***************************//
        buff->Clear();                  //clear data
        updated=true;
        //
        if(type==m_Image)
        {
            buff->Set( GL_LINES , 0 , true);

            for(uint a=0 ; a<ME.size(); a++)
            {
                mPointArray points = ME[a]->ToArray(0.01);
                if( ME[a]->F()==1)
                {
                    for(uint b=0 ; b<points.size(); b++)
                    {
                        buff->Vert(points[b],1,0,0,1,mP(0,0,0),a);
                    }
                }
                else
                {
                    for(uint b=0 ; b<points.size(); b++)
                    {
                        buff->Vert(points[b],0,0,0,1,mP(0,0,0),a);
                    }
                }
            }
        }
        else if(type==m_Chain)
        {
            buff->Set( GL_LINES , 0 , true);
            for(uint a=0 ; a<ME.size(); a++)
            {
                mPointArray points = ME[a]->ToArray(0.01);
                if( ME[a]->F()==1)
                {
                    for(uint b=0 ; b<points.size(); b++)
                    {
                        buff->Vert(points[b],0.5,0.5,1,1,mP(0,0,0),a);
                    }
                }
                else
                {
                    for(uint b=0 ; b<points.size(); b++)
                    {
                        buff->Vert(points[b],0.5,0.5,1,1,mP(0,0,0),a);
                    }
                }
            }
            //ARROW
            uint last = buff->vbuf.size()-1;

            buff->Vert(mP( buff->vbuf[last].x , buff->vbuf[last].y ),0.5,0.5,1,1,mP(0,0,0),0);

            mPoint p1 = mP(buff->vbuf[last].x,buff->vbuf[last].y).GetFromPoint(       mP(buff->vbuf[last].x,buff->vbuf[last].y).GetDirectionXY(  mP(buff->vbuf[last-1].x,buff->vbuf[last-1].y)  )-0.4,5);
            buff->Vert(p1,0.5,0.5,1,1,mP(0,0,0),0);
            mPoint p2 = mP(buff->vbuf[last].x,buff->vbuf[last].y).GetFromPoint(       mP(buff->vbuf[last].x,buff->vbuf[last].y).GetDirectionXY(  mP(buff->vbuf[last-1].x,buff->vbuf[last-1].y)  )+0.4,5);
            buff->Vert(p1,0.5,0.5,1,1,mP(0,0,0),0);
            buff->Vert(p2,0.5,0.5,1,1,mP(0,0,0),0);
            buff->Vert(p2,0.5,0.5,1,1,mP(0,0,0),0);
            buff->Vert(mP( buff->vbuf[last].x , buff->vbuf[last].y ),0,0,1,1,mP(0,0,0),0);



        }
        else if(type==m_Mesh)
        {
            buff->Set( GL_TRIANGLES , 4 , true);
            //new***************************//
            buff->vbuf.clear();                  //clear data

            for(uint a=0 ; a<ME.size(); a++)
            {
                mPoint U,V,N;

                U.SetValue(ME[a]->p2().x-ME[a]->p1().x,ME[a]->p2().y-ME[a]->p1().y,ME[a]->p2().z-ME[a]->p1().z);
                V.SetValue(ME[a]->p3().x-ME[a]->p1().x,ME[a]->p3().y-ME[a]->p1().y,ME[a]->p3().z-ME[a]->p1().z);
                N.SetValue((U.y*V.z)-(U.z*V.y),(U.z*V.x)-(U.x*V.z),(U.x*V.y)-(U.y*V.x));
                N.normalize();

                buff->Vert(   ME[a]->p1()  ,1,0,0,1, N ,a);
                buff->Vert(   ME[a]->p2()  ,1,0,0,1, N ,a);
                buff->Vert(   ME[a]->p3()  ,1,0,0,1, N ,a);
            }
        }
        //if nothing add something
        if(ME.size()==0)
        {
            buff->Set( GL_POINTS , 0 , true );
            buff->Vert(mP(10000000,10000000),1,1,1,1,mP(0,0,0),16000000);
            buff->Vert(mP(10000000,10000000),1,1,1,1,mP(0,0,0),16000000);
            buff->Vert(mP(10000000,10000000),1,1,1,1,mP(0,0,0),16000000);
            buff->Vert(mP(10000000,10000000),1,1,1,1,mP(0,0,0),16000000);
            buff->Vert(mP(10000000,10000000),1,1,1,1,mP(0,0,0),16000000);
            buff->Vert(mP(10000000,10000000),1,1,1,1,mP(0,0,0),16000000);
        }
        updated=false;
        return true;
    }
    return false;
}
//Global Functions
double GetToolOffset(double Y,Image * T,Image * C)
{
    mArea D;
    for(uint t=0; t<T->ME.size(); t++)
    {
        for(uint c=0; c<C->ME.size(); c++)
        {
            //check bounding box match....
            if(((T->ME.at(t)->H.y+Y) > C->ME.at(c)->L.y) &&  ((T->ME.at(t)->L.y+Y) < C->ME.at(c)->H.y)  )
            {
                //END POINT TEST.... WITH ELEMENT
                D.test(C->Ray(c,mP(0,Y+T->ME.at(t)->p1().y,0),mP(100,Y+T->ME.at(t)->p1().y,0)).L.x-T->ME.at(t)->p1().x);
                D.test(C->Ray(c,mP(0,Y+T->ME.at(t)->p2().y,0),mP(100,Y+T->ME.at(t)->p2().y,0)).L.x-T->ME.at(t)->p2().x);
                D.test(C->ME.at(c)->p1().x-T->Ray(t,mP(0,-Y+C->ME.at(c)->p1().y,0),mP(100,-Y+C->ME.at(c)->p1().y,0)).H.x);
                D.test(C->ME.at(c)->p2().x-T->Ray(t,mP(0,-Y+C->ME.at(c)->p2().y,0),mP(100,-Y+C->ME.at(c)->p2().y,0)).H.x);

                //TOOL ARC LINE
                if(T->ME.at(t)->T()>1 && C->ME.at(c)->T()==1)
                {

                    if(IsInArc(T->ME.at(t)->a1 ,T->ME.at(t)->a2 ,C->ME.at(c)->a1 + 1.570796325) )
                    {
                        mPoint p1 = T->ME.at(t)->cp().GetFromPoint( C->ME.at(c)->a1 + 1.570796325 , T->ME.at(t)->r );
                        D.test( C->Ray(c,mP(p1.x,p1.y+Y,p1.z),mP(p1.x+100,p1.y+Y,p1.z)).L.x-p1.x);
                    }

                    if(IsInArc(T->ME.at(t)->a1 ,T->ME.at(t)->a2 ,C->ME.at(c)->a1 - 1.570796325) )
                    {
                        mPoint p2 = T->ME.at(t)->cp().GetFromPoint( C->ME.at(c)->a1 - 1.570796325 , T->ME.at(t)->r );
                        D.test( C->Ray(c,mP(p2.x,p2.y+Y,p2.z),mP(p2.x+100,p2.y+Y,p2.z)).L.x-p2.x);
                    }
                }
                //TOOL LINE ARC
                if(T->ME.at(t)->T()==1 && C->ME.at(c)->T()>1)
                {
                    //From
                    if(IsInArc(C->ME.at(c)->a1 ,C->ME.at(c)->a2 ,T->ME.at(t)->a1 + 1.570796325) )
                    {
                        mPoint p1 = C->ME.at(c)->cp().GetFromPoint( T->ME.at(t)->a1 + 1.570796325 , C->ME.at(c)->r );
                        D.test(p1.x - T->Ray(t,mP(p1.x,-Y+p1.y,p1.z),mP(p1.x+100,-Y+p1.y,p1.z)).H.x);
                    }

                    if(IsInArc(C->ME.at(c)->a1 ,C->ME.at(c)->a2 ,T->ME.at(t)->a1 - 1.570796325) )
                    {
                        mPoint p2 = C->ME.at(c)->cp().GetFromPoint( T->ME.at(t)->a1 - 1.570796325 , C->ME.at(c)->r );
                        D.test(p2.x - T->Ray(t,mP(p2.x,-Y+p2.y,p2.z),mP(p2.x+100,-Y+p2.y,p2.z)).H.x);
                    }
                }

                //TOOL ARC ARC
                if(T->ME.at(t)->T()>1 && C->ME.at(c)->T()>1)
                {
                    double y1,y2,y3,y4,px2=0,A;
                    double pr = T->ME.at(t)->r + C->ME.at(c)->r;  //ULKOPUOLI..
                    double py = (T->ME.at(t)->cp().y+Y) - C->ME.at(c)->cp().y;
                    double px = sqrt((pr*pr)-(py*py)); //ydistyneet r..ulkopuoli

                    if(T->ME.at(t)->r>C->ME.at(c)->r)
                    {
                        double px2 = sqrt((T->ME.at(t)->r*T->ME.at(t)->r)-(py*py));
                        A = mP(0,py,0).GetDirectionXY(mP(px2,0,0));
                        y3 = T->ME.at(t)->cp().GetFromPoint(A,T->ME.at(t)->r).y+Y;
                        y4 = T->ME.at(t)->cp().GetFromPoint(A+PI,T->ME.at(t)->r).y+Y;
                    }
                    else
                    {
                        double px2 = sqrt((C->ME.at(c)->r*C->ME.at(c)->r)-(py*py));
                        A = mP(0,py,0).GetDirectionXY(mP(px2,0,0));
                        y3 = C->ME.at(c)->cp().GetFromPoint(A,C->ME.at(c)->r).y;
                        y4 = C->ME.at(c)->cp().GetFromPoint(A+PI,C->ME.at(c)->r).y;
                    }

                    A = mP(0,py,0).GetDirectionXY(mP(px,0,0));
                    y1 = T->ME.at(t)->cp().GetFromPoint(A,T->ME.at(t)->r).y+Y;
                    y2 = T->ME.at(t)->cp().GetFromPoint(A+PI,T->ME.at(t)->r).y+Y;

                    D.test( C->Ray(c,mP(0,y1,0),mP(100,y1,0)).L.x  -  T->Ray(t,mP(0,-Y+y1,0),mP(100,-Y+y1,0)).H.x);
                    D.test( C->Ray(c,mP(0,y2,0),mP(100,y2,0)).L.x  -  T->Ray(t,mP(0,-Y+y2,0),mP(100,-Y+y2,0)).H.x);
                    D.test( C->Ray(c,mP(0,y3,0),mP(100,y3,0)).L.x  -  T->Ray(t,mP(0,-Y+y3,0),mP(100,-Y+y3,0)).H.x);
                    D.test( C->Ray(c,mP(0,y4,0),mP(100,y4,0)).L.x  -  T->Ray(t,mP(0,-Y+y4,0),mP(100,-Y+y4,0)).H.x);
                }
            }
        }
    }
    return D.L.x;
}
//******************************************************************************************************************//
//**                                                                                                              **//
//**                               CHAIN FUNCTIONS                                                                **//
//**                                                                                                              **//
//******************************************************************************************************************//
mPoint Image::P1(int sel)
{
    mPoint P;
    if(ME[sel]->direction) return ME[sel]->p1();
    else return ME[sel]->p2();
}
mPoint Image::P2(int sel)
{
    if(ME[sel]->direction) return ME[sel]->p2();
    else return ME[sel]->p1();
}

mPoint Image::PC(int sel)
{
    return ME[sel]->cp();
}

int Image::T(int sel)
{
    if(ME[sel]->T()==1) return 1;
    if(ME[sel]->T()==3 && (!ME[sel]->direction) ) return 2;
    if(ME[sel]->T()==3 && ME[sel]->direction ) return 3;
}
double Image::R(int sel)
{
    return ME[sel]->r;
}
double Image::A1(int sel)
{
    if(ME[sel]->direction)return ME[sel]->a1;
    else return ME[sel]->a2;
}
double Image::A2(int sel)
{
    if(ME[sel]->direction)return ME[sel]->a2;
    else return ME[sel]->a1;
}


uint Image::Size()
{
    return ME.size();
}

//Chain to G
wxString Image::CTG(double r,double z,bool entry)
{
    wxString CODE;
    if(Size()>16000000)return _("ERR NO CHAIN Image::CTG\n");
    if(entry)
    {
        CODE = wxString::Format(_("G0X%1.3fY%1.3f\nZ%1.3f\n"),P1(0).x,P1(0).y,r);
        CODE << wxString::Format(_("G1Z%1.3f\n"),z);
    }
    else
        CODE = wxString::Format(_("G0X%1.3fY%1.3f\nZ%1.3f\n"),P1(0).x,P1(0).y,z);


    for(uint a=0; a<Size(); a++)
    {
        //G0
        if(T(a)==0)
        {
            CODE << _("G0");
            if(!AER(P2(a).x,P1(a).x)) CODE << wxString::Format(_("X%1.3f"),P2(a).x);
            if(!AER(P2(a).y,P1(a).y)) CODE << wxString::Format(_("Y%1.3f"),P2(a).y);
            if(!AER(P2(a).z,P1(a).z) && !isnan(P2(a).z) ) CODE << wxString::Format(_("Z%1.3f"),P2(a).z);
            CODE << _("\n");
        }
        //G1
        if(T(a)==1)
        {
            CODE << _("G1");
            if(!AER(P2(a).x,P1(a).x)) CODE << wxString::Format(_("X%1.3f"),P2(a).x);
            if(!AER(P2(a).y,P1(a).y)) CODE << wxString::Format(_("Y%1.3f"),P2(a).y);
            if(!AER(P2(a).z,P1(a).z)) CODE << wxString::Format(_("Z%1.3f"),P2(a).z);
            CODE << _("\n");
        }

        //G2
        if(T(a)==2)
        {
            double I = PC(a).x - P1(a).x;
            double J = PC(a).y - P1(a).y;
            //double K = PC(a).z - P1(a).z;

            CODE << _("G2");
            if(!AER(P2(a).x,P1(a).x)) CODE << wxString::Format(_("X%1.3f"),P2(a).x);
            if(!AER(P2(a).y,P1(a).y)) CODE << wxString::Format(_("Y%1.3f"),P2(a).y);
            if(!AER(P2(a).z,P1(a).z)) CODE << wxString::Format(_("Z%1.3f"),P2(a).z);
            if(!AER(I,0)) CODE << wxString::Format(_("I%1.3f"),I);
            if(!AER(J,0)) CODE << wxString::Format(_("J%1.3f"),J);
            //if(!AER(K,0)) CODE << wxString::Format(_("K%1.3f"),K);
            CODE << _("\n");

        }
        //G3
        if(T(a)==3)
        {
            double I = PC(a).x - P1(a).x;
            double J = PC(a).y - P1(a).y;
            //double K = PC(a).z - P1(a).z;

            CODE << _("G3");
            if(!AER(P2(a).x,P1(a).x)) CODE << wxString::Format(_("X%1.3f"),P2(a).x);
            if(!AER(P2(a).y,P1(a).y)) CODE << wxString::Format(_("Y%1.3f"),P2(a).y);
            if(!AER(P2(a).z,P1(a).z)) CODE << wxString::Format(_("Z%1.3f"),P2(a).z);
            if(!AER(I,0)) CODE << wxString::Format(_("I%1.3f"),I);
            if(!AER(J,0)) CODE << wxString::Format(_("J%1.3f"),J);
            //if(!AER(K,0)) CODE << wxString::Format(_("K%1.3f"),K);
            CODE << _("\n");
        }
    }
    CODE << wxString::Format(_("G0Z%1.3f\n"),r);
    return CODE;
}


bool Image::ArcToArcOffset(mPoint *p,mPoint cp1,mPoint p1 ,mPoint cp2,double r1,double r2)
{

    mPoint T;
    double rotaatio = cp1.GetDirectionXY(cp2);

    T = cp2.Translate(cp1);  //center this
    T = T.Rotate(-rotaatio);

    p1 = p1.Translate(cp1);
    p1 = p1.Rotate(-rotaatio);

    //no hit
    if((r1+r2)<T.x && !AER(r1+r2,T.x))
        return false;

    double kX=( (T.x*T.x)+(r1*r1) - (r2*r2) ) / (2*T.x) ;
    double kY = sqrt( (r1*r1) - (kX*kX));

    if(isnan(kY))kY=0;
    if(p1.y<0)
    {
        T.SetValue(kX,-kY,T.z);
    }
    else
    {
        T.SetValue(kX,kY,T.z);
    }
    T = T.Rotate(rotaatio);
    T = T.Translate(-cp1);
    p->SetValue(T.x,T.y,T.z);
    return true;
};

bool Image::LineToArcOffset(mPoint *p,mPoint p1,mPoint p2,mPoint cp,long D,double o)
{
    double radius=0;
    mPointArray pa;

    if(D==2)radius = cp.GetDistanceXY(p2)+o;
    if(D==3)radius = cp.GetDistanceXY(p2)-o;

    double angle= p1.GetDirectionXY(p2)+1.570796325;
    mPoint mp1 = p1.GetFromPoint(angle,o);
    mPoint mp2 = p2.GetFromPoint(angle,o);

    //pa = Int_CircleRay(cp,radius,mp1,mp2);

    eC(cp,radius).Intersection(&pa,eR(mp1,mp2));

    if(pa.size()==0)
        return false;

    if(pa.size()==1)
    {
        p->x=pa.at(0).x;
        p->y=pa.at(0).y;
        p->z=pa.at(0).z;
        return true;
    }

    if(cp.GetDistanceXY(mp1)>cp.GetDistanceXY(mp2))
    {
        p->x=pa.at(1).x;
        p->y=pa.at(1).y;
        p->z=pa.at(1).z;
    }
    else
    {
        p->x=pa.at(0).x;
        p->y=pa.at(0).y;
        p->z=pa.at(0).z;
    }
    return true;

};

bool Image::LineToLineOffset(mPoint *p,mPoint p1,mPoint p2,mPoint p3,double o)
{
    double k1 = p2.GetDirectionXY(p1);
    double k2 = p2.GetDirectionXY(p3);

    //Get Bisector
    double K3,k3;
    if(k1>k2)
    {
        K3=(k1-k2)/2;
        k3=k2+K3;
    }
    else
    {
        K3=((6.2831853-k2)+k1)/2;
        k3=k1-K3;
    }
    o=o/sin(K3);

    double xl=cos(k3)*o;
    double yl=sin(k3)*o;

    p->SetValue(xl+p2.x,yl+p2.y,p2.z);
    return true;
};

bool isPointInsideTriangle(mPoint v0,mPoint v1,mPoint v2,mPoint pt)
{
    v0.z=0;
    v1.z=0;
    v2.z=0;

    mPoint u = v1 - v0;
    mPoint v = v2 - v0;
    mPoint w = pt - v0;
    double uu = u.dot(u);
    double uv = u.dot(v);
    double vv = v.dot(v);

    double wu = w.dot(u);
    double wv = w.dot(v);
    double d = uv * uv - uu * vv;

    double invD = 1 / d;
    double s = (uv * wv - vv * wu) * invD;
    if (s < 0 || s > 1)
        return false;
    double t = (uv * wu - uu * wv) * invD;
    if (t < 0 || (s + t) > 1)
        return false;
    if(isnan(s) || isnan(t) ) return false;


    return true;
}



//**********************************//
bool Image::Offset(double o,Image * W)
{
    if(!MakeChain())return false;
    MakeChain();
    W->Clear();

    mPoint p1,p2;

    if(Size()>16000000)return false;

    double radius=0,radius2=0;

    if(T(0)==2)
    {
        radius = R(0)-o;
        if(radius<0)
        {
            W->Clear();
            return false;
        }
    }

    if(T(0)==3)
    {
        radius = R(0)+o;
        if(radius<0)
        {
            W->Clear();
            return false;
        }
    }
    //StartLine
    if(T(0)==1)
    {
        p1.SetValue(P1(0).GetFromPoint(P1(0).GetDirectionXY(P2(0))-1.570796325,o));
        p2.SetValue(P2(0).GetFromPoint(P1(0).GetDirectionXY(P2(0))-1.570796325,o));
        W->add(eL(p1,p2));
    }


    if(T(0)==3)
    {
        p1.SetValue( PC(0).GetFromPoint(PC(0).GetDirectionXY(P1(0)),radius));
        p2.SetValue( PC(0).GetFromPoint(PC(0).GetDirectionXY(P2(0)),radius));
        W->add(eA(p1,p2,radius));
    }
    if(T(0)==2)
    {
        p1.SetValue( PC(0).GetFromPoint(PC(0).GetDirectionXY(P1(0)),radius));
        p2.SetValue( PC(0).GetFromPoint(PC(0).GetDirectionXY(P2(0)),radius));
        W->add(eA(p2,p1,radius));
        W->ME[0]->direction = false;
    }

    //********************************//
    //**
    //**         Prosessi           **//
    //**
    //********************************//
    uint subseg = 0;                //**
    for(uint seg=0; seg<Size()-1; seg++)
    {
        //RADIUS....
        if(T(seg)==2)
        {
            radius = R(seg)-o;
            if(radius<0)
            {
                W->Clear();
                return false;
            }
        }

        if(T(seg)==3)
        {
            radius = R(seg)+o;
            if(radius<0)
            {
                W->Clear();
                return false;
            }
        }

        //line to line
        if(T(seg)==1 && T(seg+1)==1)
        {
            printf("G1G1\n");
            //W.Add( cP( p1,PC(seg),1));
            LineToLineOffset(&p1,P1(seg),P2(seg),P2(seg+1),-o);
            p2.SetValue(P2(seg+1).GetFromPoint(  P2(seg+1).GetDirectionXY(P2(seg))+1.570796325,o));
            W->ME[subseg]->at(1) = p1;
            W->add(eL(p1,p2));
            subseg++;
            continue;
        }

        //G3 to G1
        if(T(seg)==3 && T(seg+1)==1)
        {
            if(!LineToArcOffset(&p1,P2(seg+1),P2(seg),PC(seg),2,o))
            {
                printf("error G3G1\n");

                // p1.SetValue(P2(seg).GetFromPoint(P2(seg).GetDirectionXY(PC(seg)),-o));
                // W.Add( cP( p1,P2(seg),172) );
                // p1.SetValue(P2(seg).GetFromPoint( P2(seg).GetDirectionXY(P2(seg+1))-1.570796325,o)   );
                continue;
            }
            else
            {
                if( W->ME[subseg]->direction ) W->ME[subseg]->at(1) = p1;
                else W->ME[subseg]->at(0) = p1;

                p2.SetValue(P2(seg+1).GetFromPoint(P1(seg+1).GetDirectionXY(P2(seg+1))-1.570796325,o));
                W->add(eL(p1,p2));
                subseg++;
            }

        }


        //G1 to G3
        if(T(seg)==1 && T(seg+1)==3)
        {
            if(!LineToArcOffset(&p1,P1(seg),P2(seg),PC(seg+1),3,-o))
            {
                printf("error G1G3\n");
                //p1.SetValue(P2(seg).GetFromPoint( P1(seg).GetDirectionXY(P2(seg))-1.570796325,o)   );
                //W.Add( cP( p1,P2(seg),172) );
                //p1.SetValue(P2(seg).GetFromPoint(P2(seg).GetDirectionXY(PC(seg+1)),-o));
                continue;
            }
            else
            {
                if( W->ME[subseg]->direction ) W->ME[subseg]->at(1) = p1;
                else W->ME[subseg]->at(0) = p1;
                p2.SetValue( PC(seg+1).GetFromPoint(PC(seg+1).GetDirectionXY(P2(seg+1)),R(seg+1)+o ));
                W->add(eA(p1,p2,R(seg+1)+o));
                subseg++;
            }


        }

        //G2 to G1
        if(T(seg)==2 && T(seg+1)==1)
        {
            if(!LineToArcOffset(&p1,P2(seg+1),P2(seg),PC(seg),3,o))
            {
                printf("error G2G1\n");
                //p1.SetValue(P2(seg).GetFromPoint(P2(seg).GetDirectionXY(PC(seg)),o));
                //W.Add(cP(p1,P2(seg),173));
                //p1.SetValue(P2(seg).GetFromPoint( P2(seg).GetDirectionXY(P2(seg+1))-1.570796325,o)   );
                continue;
            }
            else
            {
                if( W->ME[subseg]->direction ) W->ME[subseg]->at(1) = p1;
                else W->ME[subseg]->at(0) = p1;

                p2.SetValue(P2(seg+1).GetFromPoint(P1(seg+1).GetDirectionXY(P2(seg+1))-1.570796325,o));
                W->add(eL(p1,p2));
                subseg++;
            }
        }

        //G1 to G2
        if(T(seg)==1 && T(seg+1)==2)
        {
            //W.Add(cP(p1,PC(seg),1));
            if(!LineToArcOffset(&p1,P1(seg),P2(seg),PC(seg+1),2,-o))
            {
                printf("error G1G2\n");
                //end
                // p1.SetValue(P2(seg).GetFromPoint( P1(seg).GetDirectionXY(P2(seg))-1.570796325,o)   );
                // W.Add(cP(p1,P2(seg),173));
                // p1.SetValue(P2(seg).GetFromPoint(P2(seg).GetDirectionXY(PC(seg+1)),o));
                continue;
            }
            else
            {
                if( W->ME[subseg]->direction ) W->ME[subseg]->at(1) = p1;
                else W->ME[subseg]->at(0) = p1;
                p2.SetValue( PC(seg+1).GetFromPoint(PC(seg+1).GetDirectionXY(P2(seg+1)),R(seg+1)-o ));
                W->add(eA(p2,p1,R(seg+1)-o));
                subseg++;
                W->ME[subseg]->direction = false;
            }

        }

        //G2 to G2
        if(T(seg)>1 && T(seg+1)>1)
        {
            if(T(seg)==2)
            {
                radius = R(seg)-o;
                if(radius<0)
                {
                    W->Clear();
                    return false;
                }
            }

            if(T(seg)==3)
            {
                radius = R(seg)+o;
                if(radius<0)
                {
                    W->Clear();
                    return false;
                }
            }

            if(T(seg+1)==2)
            {
                radius2 = R(seg+1)-o;
                if(radius2<0)
                {
                    W->Clear();
                    return false;
                }
            }

            if(T(seg+1)==3)
            {
                radius2 = R(seg+1)+o;
                if(radius2<0)
                {
                    W->Clear();
                    return false;
                }
            }

            if(!ArcToArcOffset(&p1,PC(seg),P2(seg),PC(seg+1),radius,radius2))
            {
                printf(" ERROR NOT SUPPORTED YET G2 3-->G2 3\n");
            }


            if(T(seg+1)==2)
            {
                if( W->ME[subseg]->direction ) W->ME[subseg]->at(1) = p1;
                else W->ME[subseg]->at(0) = p1;
                p2.SetValue( PC(seg+1).GetFromPoint(PC(seg+1).GetDirectionXY(P2(seg+1)),R(seg+1)-o ));
                W->add(eA(p2,p1,R(seg+1)-o));
                subseg++;
                W->ME[subseg]->direction = false;
            }
            if(T(seg+1)==3)
            {
                if( W->ME[subseg]->direction ) W->ME[subseg]->at(1) = p1;
                else W->ME[subseg]->at(0) = p1;
                p2.SetValue( PC(seg+1).GetFromPoint(PC(seg+1).GetDirectionXY(P2(seg+1)),R(seg+1)+o ));
                W->add(eA(p1,p2,R(seg+1)+o));
                subseg++;
            }
        }
    }
    return true;
};
